////////////////////////////////////////////////////////////////////////
// This file is part of the simpleSID framework 
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
//
// Copyright (c)Richard White, 2009
// See License.txt for a disclaimer of all warranties
// and licensing information

#include <stdafx.h>
#include "Envelope.h"

const unsigned short Envelope::m_wLFSRTable[] = {	0x7f00,
													0x0006,
													0x003c,
													0x0330,
													0x20c0,
													0x6755,
													0x3800,
													0x500e,
													0x1212,
													0x0222,
													0x1848,
													0x59b8,
													0x3840,
													0x77e2,
													0x7625,
													0x0a93	};

const unsigned char Envelope::m_byExponentialPeriodTable[] = {	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
																0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };

const unsigned char Envelope::m_bySustainLevelTable[] = {	0x00, 
															0x11, 
															0x22, 
															0x33, 
															0x44, 
															0x55, 
															0x66, 
															0x77, 
															0x88, 
															0x99, 
															0xaa, 
															0xbb, 
															0xcc, 
															0xdd, 
															0xee, 
															0xff };

Envelope::Envelope()
{
	Reset();
}

Envelope::~Envelope()
{
	//nothing to be seen here move along
}

void Envelope::Reset()
{
	m_bGate = false;
	m_bActive = false;

	m_byAttack = 0;
	m_byDecay = 0;
	m_bySustain = 0;
	m_byRelease = 0;

	m_wLFSR = 0x7fff;
	m_State = kRelease;
	m_byExponentialCounter = 0;
	m_byExponentialPeriod = 1;
	m_wLFSRPeriod = m_wLFSRTable[m_byRelease];
	m_byEnvelopeLevel = 0;



}

void Envelope::Process()
{
	if (m_wLFSR == m_wLFSRPeriod)
	{
		m_wLFSR = 0x7fff;
		m_byExponentialCounter++;
		if ((m_State == kAttack) || (m_byExponentialCounter == m_byExponentialPeriod))
		{
			m_byExponentialCounter = 0;
			if (m_bActive)
			{
				switch (m_State)
				{
				case kAttack:
					m_byEnvelopeLevel = (m_byEnvelopeLevel + 1) & 0xff;
					if (m_byEnvelopeLevel == 0xff)
					{
						m_State = kDecay;
						m_wLFSRPeriod = m_wLFSRTable[m_byDecay & 0x0f];
					}
					break;
				case kDecay:

				case kSustain:
					if (m_byEnvelopeLevel != m_bySustainLevelTable[m_bySustain])
						--m_byEnvelopeLevel;
					break;
				case kRelease:
					m_byEnvelopeLevel = (m_byEnvelopeLevel - 1) & 0xff;
					break;
				}

				m_byEnvelopeLevel = m_byEnvelopeLevel & 0xff;
				unsigned char byExpPeriod = m_byExponentialPeriodTable[m_byEnvelopeLevel];
				if (byExpPeriod != 0)
					m_byExponentialPeriod = byExpPeriod;

				if (m_byEnvelopeLevel == 0)
					m_bActive = false;
			}
		}
	}
	else
		m_wLFSR = ((m_wLFSR << 1) | (((m_wLFSR >> 14) ^ (m_wLFSR >> 13)) & 1)) & 0x7fff;
}

unsigned char Envelope::Output()
{
	return m_byEnvelopeLevel;
}

void Envelope::SetGate(bool bGate)
{
	if (!m_bGate && bGate)
	{
		m_State = kAttack;
		m_wLFSRPeriod = m_wLFSRTable[m_byAttack & 0x0f];
		m_bActive = true;
	}
	else if (m_bGate && !bGate)
	{
		m_State = kRelease;
		m_wLFSRPeriod = m_wLFSRTable[m_byRelease & 0x0f];
	}
	
	m_bGate = bGate;
}

void Envelope::SetAttackDecay(unsigned char byAD)
{
	m_byAttack = (byAD >> 4) & 0x0f;
	m_byDecay = byAD & 0x0f;

	if (m_State == kAttack)
		m_wLFSRPeriod = m_wLFSRTable[m_byAttack & 0x0f];
	if (m_State == kDecay)
		m_wLFSRPeriod = m_wLFSRTable[m_byDecay & 0x0f];
}

void Envelope::SetSustainRelease(unsigned char bySR)
{
	m_bySustain = (bySR >> 4) & 0x0f;
	m_byRelease = bySR & 0x0f;
	
	if (m_State == kRelease)
		m_wLFSRPeriod = m_wLFSRTable[m_byRelease & 0x0f];
}

unsigned char Envelope::GetAttack()
{
	return m_byAttack;
}

unsigned char Envelope::GetDecay()
{
	return m_byDecay;
}

unsigned char Envelope::GetSustain()
{
	return m_bySustain;
}

unsigned char Envelope::GetRelease()
{
	return m_byRelease;
}

void Envelope::SetAttack(unsigned char byAttack)
{
	m_byAttack = byAttack & 0x0f;

	if (m_State == kAttack)
		m_wLFSRPeriod = m_wLFSRTable[m_byAttack];
}

void Envelope::SetDecay(unsigned char byDecay)
{
	m_byDecay = byDecay & 0x0f;

	if (m_State == kDecay)
		m_wLFSRPeriod = m_wLFSRTable[m_byDecay];
}

void Envelope::SetSustain(unsigned char bySustain)
{
	m_bySustain = bySustain & 0x0f;
}

void Envelope::SetRelease(unsigned char byRelease)
{
	m_byRelease = byRelease & 0x0f;

	if (m_State == kRelease)
		m_wLFSRPeriod = m_wLFSRTable[m_byRelease];
}

unsigned char Envelope::ReadEnvelope()
{
	return Output();
}
